import sys, traceback
from compiler import compile
from xml.sax.saxutils import escape
from re import compile as re_compile

OBJECT_PATTERN = re_compile(r'__objects__\[\d+\]')

class Executor:
    def _execute_(self, text, input, main):
        self.ExecutionResults = []
        label = 'Input(type="%s", id="%s")'%(str(input.type), str(input.ID))
        
        #compile commands (can give syntax errors)
        try:
            c = compile(text, label, 'exec')
        except:
            type, value, tb = sys.exc_info()
            type = "<type>%s</type>"%escape(str(type))
            value = "<value>%s</value>"%escape(str(value))
            error = "<symbide_error>%s%s</symbide_error>"%(type, value)
            input._objects.append(error)
            self.ExecutionResults.append('__objects__[%s]\n'%str(len(input._objects)-1))
            return
        
        #Switch the standard output to the intern log
        self.stdout = sys.stdout
        sys.stdout = self
        
        #Run the commands through the python-interpreter
        try:
            exec c in input.global_namespace, input.local_namespace
        except:
            type, value, tb = sys.exc_info()
            trace = traceback.extract_tb(tb)
            lines = text.split('\n')
            
            for i in range(len(trace)):
                if trace and len(trace[i])==4 and trace[i][0]==label:
                    trace[:i] = []
                    break
            for i in range(len(trace)):
                trace[i] = list(trace[i])
                if trace[i][0]==label:
                    trace[i][3] = lines[trace[i][1]-1].strip(' \t')
            trace = "<trace>%s</trace>"%escape(str(trace))
            type = "<type>%s</type>"%escape(str(type))
            value = "<value>%s</value>"%escape(str(value))
            error = "<symbide_error>%s%s%s</symbide_error>"%(trace, type, value)
            input._objects.append(error)
            self.ExecutionResults.append('__objects__[%s]\n'%str(len(input._objects)-1))
        
        #Reset the standard output
        sys.stdout = self.stdout
    
    def replaceObjects(self, text, input):
        text = escape(text)
        def subst(word):
            name = word.group()
            p1 = name.find('[')+1
            p2 = name.find(']')
            return input._objects[int(name[p1:p2])]
        return OBJECT_PATTERN.sub(subst, text)
    
    def write(self, data):
        '''
        This is neccessary to capture the stdout of the executed commands
        '''
        
        self.ExecutionResults.append(data)
        